/*
 * Classe de manipulacao de conexoes de SGBD 
 *   e execucao de instrucoes SQL
 *
 */

package org.jerm.Conectividade;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SGBD
{
    protected String SGBD;
    protected String Driver;
    protected String URL;
    protected String Servidor;
    protected String Usuario;
    protected String Senha;
    protected String Porta;
    protected String BD;
    
    protected Boolean Status;
    protected Boolean Configurado=false;
    
    protected Connection Connection;
    protected Object DriverInstance;

    public SGBD(){

        this.Servidor = new String();
        this.Driver = new String();
        this.URL = new String();
        this.Usuario = new String();
        this.Senha = new String();
        this.Porta = new String();
        this.BD = new String();
        
        setStatus(false);
        
        this.Connection = null;
        
    }
    
    public boolean getRealStatus(){
        return this.Status.booleanValue();
    }
    
    /**
     * Instancia classe SGBD
     * @param Driver Driver usado na conexao
     * @param Servidor Endereco do SGBD
     * @param User Usuario do SGBD
     * @param Password Senha do SGBD
     * @param Porta Porta usada na conexao com o SGBD
     * @param BD Banco de dados desejado
     */
    public SGBD (String Driver, String Servidor, String User, String Password, String Porta, String BD){

        this.Servidor = new String();
        this.Driver = new String();
        this.URL = new String();
        this.Usuario = new String();
        this.Senha = new String();
        this.Porta = new String();
        this.BD = new String();
        
        setServidor(Servidor);
        setPorta(Porta);
        setBD(BD);
        setDriver(Driver);
        setUsuario(User);
        setSenha(Password);
        setURL();        
        setSGBD(Driver);

        setStatus(false);
        
        this.Connection = null;
    }
    
    /**
     * Atribui SGBD ("mysql" ou "postgresql"
     * @param SGBD Nome do SGBD
     */
    public void setSGBD (String SGBD){
        this.SGBD = SGBD;
        setURL();
    }
    
    /**
     * Atribui usu???rio SGBD
     * @param Usuario Usuario do SGBD
     */
    public void setUsuario (String Usuario){
        this.Usuario = Usuario;
    }
    
    /**
     * Atribui senha SGBD
     * @param Senha Senha do SGBD
     */
    public void setSenha (String Senha){
        this.Senha = Senha;
    }
    
    /**
     * Atribui porta de conexao do SGBD
     * @param Porta Porta de comunicacao (3306, 5432, etc)
     */
    public void setPorta (String Porta){
        this.Porta = Porta;
        setURL();
    }
    
    /**
     * Atribui endereco do SGBD
     * @param Servidor Endereco do servidor (localhost, etc)
     */
    public void setServidor (String Servidor){
        this.Servidor = Servidor;
        setURL();
    }
    
    /**
     * Atribui banco de dados do SGBD
     * @param BD Banco de dados do SGBD
     */
    public void setBD (String BD){
        this.BD = BD;
        setURL();
    }
    
    /**
     * Atribui URL de conexao SGBD
     */
    private void setURL (){
        this.URL = "jdbc:"+SGBD+"://"+Servidor+":"+Porta+"/"+BD;
        if(SGBD!="" && Servidor!="" && Porta!="" && BD!=""){
            Configurado=true;
            //getStatus();
        }else{
            Configurado=false;
        }
        //System.out.println(this.URL);
    }

    /**
     * Atribui Driver para o SGBD
     * @param SGBD Nome do SGBD
     */
    public void setDriver(String SGBD){
        try
        {
            
            if (SGBD == "mysql"){
                this.Driver = "com.mysql.jdbc.Driver";
            }else if (SGBD == "postgresql"){
                this.Driver = "org.postgresql.Driver";
            }
            
            setURL();            
            this.DriverInstance=Class.forName( this.Driver ).newInstance();

        } catch (Exception ex)
        {
            //ex.printStackTrace();
        }
    }    
    
    /**
     * Atribui status a conexao com o SGBD
     * @param Status Status da coexao (true ou false)
     */
    private void setStatus(Boolean Status){
        this.Status = Status;
    }
    
    /**
     * Retorna SGBD da conexao atual
     * @return SGBD SGBD da conexao atual ("mysql" ou "postgresql")
     */
    public String getSGBD (){
        return this.SGBD;
    }
    
    /**
     * Retorna SGBD da conexao atual
     * @return Usuario Usuario da conexao atual
     */
    public String getUsuario (){
        return this.Usuario;
    }
    
    /**
     * Retorna Senha da conexao atual
     * @return Senha Senha da conexao atual
     */
    public String getSenha (){
        return this.Senha;
    }

    /**
     * Retorna porta da conexao atual
     * @return Porta Porta da conexao atual (3306, 5432, etc)
     */
    public String getPorta (){
        return this.Porta;
    }
    
    /**
     * Retorna endereco da conexao atual
     * @return Servidor Endereco da conexao atual (localhost,etc)
     */
    public String getServidor (){
        return this.Servidor;
    }
    
    /**
     * Retorna banco de dados da conexao atual
     * @return BD Banco de dados da conexao atual
     */
    public String getBD (){
        return this.BD;
    }
    
    /**
     * Retorna URL da da conexao atual
     * @return URL URL da conexao atual
     */
    public String getURL (){
        return this.URL;
    }
    
    /**
     * Retorna driver na conexao atual
     * @return Driver Driver da conexao atual
     */
    public String getDriver (){
        return this.Driver;
    }
    
    /**
     * Retorna status da conexao atual
     * @return Booelan Status da conexao atual
     */
    public boolean getStatus(){
        if(!Configurado)
            return false;
        else if(Connection==null){
            return false;
        }else {
            try{
                if(this.Connection.isClosed())
                    Status=false;
            } catch (SQLException ex)
            {
                //ex.printStackTrace();
                return false;
            }
        }
        return this.Status;
    }

    /**
     * M???todo que tenta se conectar ao SGBD, retornando se conseguiu ou nao.
     * @return Status Retorna se conexao foi efetuada com sucesso ou nao
     */
    public boolean Conecta(){
        boolean Retorno;
        try
        {

            //System.out.println("url: " + getURL()+"\nuser: "+getUsuario()+ "\nsenha: "+getSenha());
            this.Connection=DriverManager.getConnection(getURL(), getUsuario(), getSenha());
            Retorno=true;

        } catch (SQLException ex)
        {
            //ex.printStackTrace();
            System.out.println("Erro de Conexao "+Integer.toString(ex.getErrorCode()));
            Status=false;
            Connection=null;
            Retorno=false;
            
        }

        setStatus(Retorno);
        return Retorno;
    }
    
    /**
     * M???todo que tenta se conectar ao SGBD, retornando se conseguiu ou nao.
     * @return Status Retorna se conexao foi efetuada com sucesso ou nao
     */
    public String ConectaTeste(){
        String Retorno;
        if(!Configurado)
            return "Favor Configurar";
        try
        {

            //System.out.println("url: " + getURL()+"\nuser: "+getUsuario()+ "\nsenha: "+getSenha());
            this.Connection=DriverManager.getConnection(getURL(), getUsuario(), getSenha());
            Retorno="Conexao com Sucesso";
            setStatus(true);

        } catch (SQLException ex)
        {
            //ex.printStackTrace();
            Retorno="Erro de Conexao "+Integer.toString(ex.getErrorCode());
            setStatus(false);
            
        }

        return Retorno;
    }

    /**
     * Desconecta do SGBD
     * @return Boolean indicando Sucesso da Operacao
     */
    public boolean Desconecta (){
        if(this.Connection != null)
        {   
            try {
                this.Connection.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
                return false;

            }
        }
        return true;
    }    
    
    /**
     * Metodo que executa instrucoes SQL no BD, 
     *    retornado no objeto RetornoSQL os resultados.
     * @param String_SQL Instrucao SQL a ser executada no BD
     * @param Tipo Tipo da instrucao 
     *      "query" para instrucoes de consulta
     *      "update" para instrucoes de atualizacao do BD
     * @return RetornoSQL Objeto que contem RecordCount, ResultSet e PreparedStatement
     *   tal como documentado em RetornoSQL.java
     */
    public RetornoSQL executaSQL(String String_SQL, String Tipo){
        Statement stmt = null;
        RetornoSQL ret = new RetornoSQL();
        int cont = 0;

        if (Tipo  == "update") {
            try {
                if (! this.getStatus()) this.Conecta();
                stmt = this.Connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            }catch (SQLException e){
                System.out.println("Erro ao Executar SQL "+e.getErrorCode()+"\n"+e.getMessage()+"\n"+e.getSQLState());
                //e.printStackTrace();
                return null;
            }
        } else if (Tipo == "query"){
            try {
                if (! this.getStatus()) this.Conecta();
                stmt = this.Connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            }catch (SQLException e){
                System.out.println("Erro ao Executar SQL "+e.getErrorCode()+"\n"+e.getMessage()+"\n"+e.getSQLState());
                //new Error("Erro ao Executar SQL "+e.getErrorCode()+"\n"+e.getMessage()+"\n"+e.getSQLState());
                //e.printStackTrace();
                return null;
            }
        }

        try {

            if (Tipo == "update") {
                if (! this.getStatus()) this.Conecta();
                cont = stmt.executeUpdate(String_SQL);
                ret.ps = null;
                ret.rs = null;
                ret.RecordCount = cont;
            }else if (Tipo == "query") {
                if (! this.getStatus()) this.Conecta();
                ret.ps = null;
                ret.rs = stmt.executeQuery(String_SQL);                
                ret.RecordCount = 0;
            }

        }catch (SQLException e) {
                System.out.println("Erro ao Executar SQL "+e.getErrorCode()+"\n"+e.getMessage()+"\n"+e.getSQLState());
                //new Error("Erro ao Executar SQL "+e.getErrorCode()+"\n"+e.getMessage()+"\n"+e.getSQLState());
            //e.printStackTrace();
            return null;
        }

        return ret;
    }

    /**
     * Metodo que executa instru??????es (preparadas) SQL no BD, 
     *    retornado no objeto RetornoSQL os resultados.
     * @param String_SQL Instru??????o SQL a ser executada no BD
     * @param Valores Vetor de valores dos parametros declarados em StringSQL
     * @param Retornos Vetor que recebe valores retornados pela instrucao
     * @param Conexao Conexao que sera usada para execucao das instrucoes
     * @return RetornoSQL Objeto que contem RecordCount, ResultSet e PreparedStatement
     *   tal como documentado em RetornoSQL.java
     */
    public RetornoSQL executaPreparedSQL(String String_SQL, String [] Valores, String [] Retornos){
        RetornoSQL ret = new RetornoSQL();
        int i, len;
        
        try {
            
            if (! this.getStatus()) this.Conecta();
            
            ret.ps = this.Connection.prepareStatement(String_SQL,Retornos);
            
            len = Valores.length;
            for(i=0; i<len; i++){
                ret.ps.setString(i+1,Valores[i]);
            }

    } catch (SQLException ex) {
            ex.printStackTrace();
            return null;
        }
        
        try {
            ret.RecordCount = ret.ps.executeUpdate();
            ret.rs = null;
            return ret;
        } catch (SQLException ex) {
            ex.printStackTrace();
            return null;
        }

    }

    /**
     * Metodo MAIN usado para testes da classe
     * @param args Vetor de Argumentos
     */
    public static void main (String args[]){
        SGBD teste = new SGBD("mysql", "tognado.homelinux.org", "mc536", "rtorres","3306", "mc536_proj2");
        teste.Conecta();
        
//        SGBD teste2 = new SGBD("postgresql", "tognado.homelinux.org", "mc536", "rtorres","5432", "mc536_proj2");
//        teste2.Conecta();

  
        
//        RetornoSQL oi = new RetornoSQL();
//        oi = teste.executaSQL("UPDATE CLIENTE","update");

        

        RetornoSQL oi = new RetornoSQL();
        oi = teste.executaSQL("SELECT * FROM CLIENTE","query");
        
        try {

            while (oi.rs.next()){

                System.out.println("=>" + oi.rs.getString("CODIGO") + "   -   " + oi.rs.getString("NOME"));
                oi.rs.next();

            }
            
        } catch (SQLException ex) {
            ex.printStackTrace();
        }

        if(teste.getStatus()){
            System.out.println("Ta Conectado");
        }else{
            System.out.println("NAO Ta Conectado");
        }
        
        teste.Desconecta();
        teste = new SGBD("mysql", "tognado.homelinux.org", "mc536", "senhaerrada","3306", "mc536_proj2");
        teste.Conecta();
        oi = teste.executaSQL("SELECT * FROM CLIENTE","query");
        
        try {

            while (oi.rs.next()){

                System.out.println("=>" + oi.rs.getString("CODIGO") + "   -   " + oi.rs.getString("NOME"));
                oi.rs.next();

            }
            
        } catch (SQLException ex) {
            ex.printStackTrace();
        }

        if(teste.getStatus()){
            System.out.println("Ta Conectado");
        }else{
            System.out.println("NAO Ta Conectado");
        }

        /*
        aux = "INSERT INTO `CLIENTE` (`NOME`, `CODIGO`, `SALDO`, `VENDAS`, `TOTAL`) VALUES   ('Crepaldi', 99, 9, 8, 7),   ('Eli', 98, 7, 6, 5)";
        oi = teste.executaSQL(aux,"update");
        aux = "CREATE TABLE alunos (ra	integer NOT NULL PRIMARY KEY, nome_aluno varchar(50), ano_admiss integer, data_nasc date)";
        oi = teste.executaSQL(aux,"update");
         */
        
        
/*
        String [] val = {"nome2", "23", "34","45","56"};
        String [] ret = {"CODIGO"};
        aux = "INSERT INTO CLIENTE (`NOME`, `CODIGO`, `SALDO`, `VENDAS`, `TOTAL`) VALUES   (?, ?, ?, ?, ?)";
        try{
            oi = teste.executaPreparedSQL(aux,val,ret);
        }catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
*/      
        teste.Desconecta();
        
    }

}